package com.lifeservice.console.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.lifeservice.common.core.redis.RedisCache;
import com.lifeservice.common.exception.ServiceException;
import com.lifeservice.common.utils.SnowFlakeUtil;
import com.lifeservice.common.utils.StringUtils;
import com.lifeservice.console.domain.LifeSchedule;
import com.lifeservice.console.domain.LifeWorkClass;
import com.lifeservice.console.domain.ScheduInfo;
import com.lifeservice.console.domain.ScheduleAddBean;
import com.lifeservice.console.mapper.LifeScheduleMapper;
import com.lifeservice.console.mapper.LifeWorkClassMapper;
import com.lifeservice.console.service.ILifeScheduleService;
import com.lifeservice.util.HolidayCrawler;
import com.lifeservice.util.LifeServiceConstants;
import com.lifeservice.util.ScheduUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestBody;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 排班Service业务层处理
 *
 * @author lifeservice
 * @date 2023-02-27
 */
@Service
public class LifeScheduleServiceImpl implements ILifeScheduleService {
    @Autowired
    private LifeScheduleMapper lifeScheduleMapper;

    @Autowired
    private LifeWorkClassMapper lifeWorkClassMapper;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private HolidayCrawler holidayCrawler;

    /**
     * 查询排班
     *
     * @param id 排班主键
     * @return 排班
     */
    @Override
    public LifeSchedule selectLifeScheduleById(String id) {
        LifeSchedule schedule = redisCache.getCacheObject(LifeServiceConstants.SCHEDULE_CACHE_PREFIX + id);
        if (null != schedule) {
            return schedule;
        }
        schedule = lifeScheduleMapper.selectLifeScheduleById(id);
        redisCache.setCacheObject(LifeServiceConstants.SCHEDULE_CACHE_PREFIX + id, schedule);
        return schedule;
    }

    /**
     * 查询排班列表
     *
     * @param lifeSchedule 排班
     * @return 排班
     */
    @Override
    public List<LifeSchedule> selectLifeScheduleList(LifeSchedule lifeSchedule) {
        return lifeScheduleMapper.selectLifeScheduleList(lifeSchedule);
    }

    /**
     * 新增排班
     *
     * @param lifeSchedule 排班
     * @return 结果
     */
    @Override
    public int insertLifeSchedule(LifeSchedule lifeSchedule) {
        return lifeScheduleMapper.insertLifeSchedule(lifeSchedule);
    }

    /**
     * 修改排班
     *
     * @param lifeSchedule 排班
     * @return 结果
     */
    @Override
    public int updateLifeSchedule(LifeSchedule lifeSchedule) {
        return lifeScheduleMapper.updateLifeSchedule(lifeSchedule);
    }

    /**
     * 批量删除排班
     *
     * @param ids 需要删除的排班主键
     * @return 结果
     */
    @Override
    public int deleteLifeScheduleByIds(String[] ids) {
        return lifeScheduleMapper.deleteLifeScheduleByIds(ids);
    }

    /**
     * 删除排班信息
     *
     * @param id 排班主键
     * @return 结果
     */
    @Override
    public int deleteLifeScheduleById(String id) {
        // 先删除缓存 再删除数据库
        redisCache.deleteObject(LifeServiceConstants.SCHEDULE_CACHE_PREFIX + id);
        redisCache.deleteObject(LifeServiceConstants.WORK_CLASS_BY_SCHEID_CACHE_PREFIX + id);
        lifeScheduleMapper.deleteWorkClassByScheduleId(id);
        return lifeScheduleMapper.deleteLifeScheduleById(id);
    }

    @Override
    public int addSchedule(@RequestBody ScheduleAddBean scheduleAddBean) throws ParseException {
        int perServiceNum = scheduleAddBean.getServeUnitSupportNum();
        int perServiceTime = scheduleAddBean.getServeUnitTime();
        List<String> serveDays = scheduleAddBean.getServeDays();
        //将节假日和周六周日剔除
        List<String> holidays = holidayCrawler.initHolidays();
        List<String> sameDay = getSameDay(serveDays, holidays);
        serveDays.removeAll(sameDay);
        if (!CollectionUtils.isEmpty(scheduleAddBean.getAppointWeeks())) {
            serveDays = getAppointWeek(serveDays, scheduleAddBean.getAppointWeeks());
        }
        if (CollectionUtils.isEmpty(serveDays)) {
            throw new ServiceException("所选日期在服务周不存在，请重新选定");
        }
        String workStartTime = scheduleAddBean.getWorkStartTime();
        String workEndTime = scheduleAddBean.getWorkEndTime();
        String sleepStartTime = scheduleAddBean.getSleepStartTime();
        String sleepEndTime = scheduleAddBean.getSleepEndTime();
        String buildingId = scheduleAddBean.getBuildingId();
        String supplierId = scheduleAddBean.getId();
        // 判断日期是否已经做过排班
        LifeSchedule query = new LifeSchedule();
        query.setSupplierId(supplierId);
        query.setBuildId(buildingId);
        List<LifeSchedule> scheduleInDbList = lifeScheduleMapper.selectLifeScheduleList(query);
        if (StringUtils.isNotEmpty(scheduleInDbList)) {
            List<String> hasDays = scheduleInDbList.stream().map(LifeSchedule::getServeDay).collect(Collectors.toList());
            List<String> intersection = serveDays.stream().filter(item -> hasDays.contains(item)).collect(Collectors.toList());
            if (StringUtils.isNotEmpty(intersection)) {
                throw new ServiceException("" + JSONObject.toJSONString(intersection) + " 日期已经排班，请重新选择排班日期", 500);
            }
        }
        List<LifeSchedule> scheduleList = new LinkedList<>();
        List<LifeWorkClass> workClassList = new LinkedList<>();
        for (String serveDay : serveDays) {
            LifeSchedule oneSchedule = new LifeSchedule();
            String scheduleId = SnowFlakeUtil.getInstance().nextId();
            oneSchedule.setId(scheduleId);
            ScheduInfo info = ScheduUtil.getScheduling(perServiceNum, perServiceTime, serveDay, workStartTime, workEndTime, sleepStartTime, sleepEndTime);
            oneSchedule.setSupplierId(supplierId);
            oneSchedule.setBuildId(buildingId);
            oneSchedule.setServeDay(serveDay);
            oneSchedule.setServeWeek(info.getWeek());
            oneSchedule.setWorkStartTime(workStartTime);
            oneSchedule.setWorkEndTime(workEndTime);
            oneSchedule.setSleepStartTime(sleepStartTime);
            oneSchedule.setSleepEndTime(sleepEndTime);
            List<LifeWorkClass> workClassListWithoutId = info.getWorkClassList();
            List<LifeWorkClass> workClassListWithId = workClassListWithoutId.stream()
                    .peek(vo -> genWorkClassInfo(vo, scheduleId))
                    .collect(Collectors.toList());
            String workClassCacheKey = LifeServiceConstants.WORK_CLASS_BY_SCHEID_CACHE_PREFIX + scheduleId;
            redisCache.setCacheList(workClassCacheKey, workClassListWithId);
            workClassList.addAll(workClassListWithId);
            scheduleList.add(oneSchedule);
            redisCache.setCacheObject(LifeServiceConstants.SCHEDULE_CACHE_PREFIX + scheduleId, oneSchedule);

        }
        if (!StringUtils.isEmpty(scheduleList)) {
            lifeScheduleMapper.batchInsertLifeSchedule(scheduleList);
        }
        int result = 0;
        if (!StringUtils.isEmpty(workClassList)) {
            result = lifeWorkClassMapper.batchInsertWorkClass(workClassList);
        }
        return result;
    }

    private void genWorkClassInfo(LifeWorkClass info, String scheduleId) {
        info.setScheduleId(scheduleId);
        info.setId(SnowFlakeUtil.getInstance().nextId());
        info.setCreateTime(new Date());
    }

    private static List<String> getSameDay(List<String> t1, List<String> t2) {
        List<String> resultList = new ArrayList<>();
        t1.stream().forEach(a1 -> {
            if (t2.contains(a1)) {
                resultList.add(a1);
            }
        });

        return resultList;
    }

    //获取指定周Xd的日期
    private static List<String> getAppointWeek(List<String> days, List<Integer> weeks) throws ParseException {
        Calendar cal = Calendar.getInstance();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        List<String> appointWeek = new ArrayList<>();
        for (String day : days) {
            //判断今天是周几
            cal.setTime(simpleDateFormat.parse(day));
            int i = cal.get(Calendar.DAY_OF_WEEK) - 1;
            if (weeks.contains(i)) {
                appointWeek.add(day);
            }
        }
        return appointWeek;
    }

}
